note
    description: "Listener thread of the server"
    author: "zistvan"
    date: "$Date$"
    revision: "$Revision$"

class
    CONNECTION_POOL
inherit

    ARGUMENTS

    INET_PROPERTIES

create
    make

feature {NONE} --init

    -- the parallel logger
    logger_instance : separate LOGGER

    -- keep the sockets so they are not garbage collected!
    sockets         : ARRAY[NETWORK_STREAM_SOCKET]

	-- stores the last user thread created
    user_thread : separate CONNECTION_THREAD

    make
        local
            port            : INTEGER
            prefer_ipv4_stack: BOOLEAN
            listen_socket    : NETWORK_STREAM_SOCKET
            accept_timeout    : INTEGER
            logging_enabled : BOOLEAN
            output_enabled     : BOOLEAN

        do
            -- default values:
            port := 8080
            logging_enabled:=true
            output_enabled:=true

            if argument_count > 0  then
                port := argument (1).to_integer
            end

            if argument_count > 1  then
                output_enabled := argument (2).to_boolean
            end

            if argument_count > 2 then
                logging_enabled := argument (3).to_boolean
            end

            -- this is where we'll store the client sockets
            create sockets.make (0, 1024)

            if output_enabled then
                print ("%N________________________________%N")
                print ("[CONNPOOL] Started on port "+port.out+"%N")
            end

            if logging_enabled then
                create logger_instance.make
            end

            -- create the server socket
            create listen_socket.make_server_by_port (port)

            -- listen for connections
            listen_loop(listen_socket,output_enabled,logging_enabled)
        end

feature --public

    listen_loop (listen_socket : NETWORK_STREAM_SOCKET; output_enabled :BOOLEAN; logging_enabled:BOOLEAN)
        local
            tid : INTEGER
        do

            if listen_socket.is_bound and then listen_socket.address /= Void
            then

                tid := 0
                listen_socket.listen (1024)
                if output_enabled=true then
                    print ("[CONNPOOL] Waiting for clients.%N")
                end

                from
                until listen_socket.is_closed
                loop

                    listen_socket.accept
                    -- if a client connected, open a port for it
                    fork_thread (tid, listen_socket, output_enabled, logging_enabled)
                    tid := tid + 1

                end
            end

            if output_enabled then
                print ("[CONNPOOL] exited%N")
            end
        end

        fork_thread (id: INTEGER; socket : NETWORK_STREAM_SOCKET; output_enabled :  BOOLEAN; logging_enabled:  BOOLEAN)
        local

            user_socket : NETWORK_STREAM_SOCKET
        do
            -- port of the client
            user_socket := socket.accepted

            -- to prevent garbage collection on the socket:
            sockets.put (user_socket, id)

            -- parallel thread to serve the client
            create user_thread.make (id, user_socket.descriptor, logger_instance, output_enabled, logging_enabled)

            if(output_enabled = true ) then
                print ("[CONNPOOL] Client #")
                print (id.out)
                print ("[CONNPOOL] with IP=")
                print (user_socket.peer_address.host_address.host_address)
                print(" conencted%N")
            end

            if(logging_enabled = true) then
                log(logger_instance, "[CONNPOOL] Client #"+id.out+" with IP " + user_socket.peer_address.host_address.host_address +" connected")
            end

            -- do the async call
            serve_client_on (user_thread)
        end


        serve_client_on (client_t : separate CONNECTION_THREAD)
        do
            client_t.serve
        end

        log(lgr : separate LOGGER; entry : STRING)
        do
            lgr.log(entry)
        end
end
